<template>
    <div style="width:100%;height:100%">
        <div style="display:flex">
            <button @click="HighPerformance">HighPerformance</button>
            <button @click="RemovePerformance">RemovePerformance</button>
            <SeptInput v-model="bloomPassA.strength" />
            <SeptInput v-model="bloomPassA.radius" />
            <SeptInput v-model="bloomPassA.threshold" />
        </div>

        <div id="3d-graph" class="graph-3d" style="height:900px"></div>
    </div>
</template>

<script>
import ForceGraph3D from "3d-force-graph";
import {
    CSS2DRenderer,
    CSS2DObject
} from "three/examples/jsm/renderers/CSS2DRenderer.js";
import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass.js";
import SpriteText from "three-spritetext";
import RES from "./ObjectJson.js";
// import THREE from "three";

import * as THREE from "three";
console.log(THREE);
export default {
    data() {
        return {
            Graph: null,
            highlightNodes: null,
            highlightLinks: null,
            hoverNode: null,
            nodes: [],
            links: [],
            maxSize: 1,
            subNodes: [],
            subLinks: [],
            bloomPassA: {
                strength: "6",
                radius: "1",
                threshold: "0"
            }
        };
    },
    watch: {
        bloomPassA: {
            handler() {
                this.HighPerformance();
            },
            deep: true
        }
    },
    mounted() {
        this.Graph = ForceGraph3D({
            extraRenderers: [new CSS2DRenderer()]
        })(document.getElementById("3d-graph"))
            .nodeThreeObject(node => {
                console.log(node);
                const imgTexture = new THREE.TextureLoader().load(
                    `/c${(node.id % 3) + 1}.png`
                );
                imgTexture.colorSpace = THREE.SRGBColorSpace;
                const material = new THREE.SpriteMaterial({
                    map: imgTexture,
                    opacity: 0.7
                });
                const sprite = new THREE.Sprite(material);
                sprite.scale.set(12, 12);
                return sprite;
                return new THREE.Mesh(
                    [
                        // 圆环
                        new THREE.TorusGeometry(3, 1),
                        // 球
                        new THREE.SphereGeometry(Math.random() * 10),
                        // 线圈
                        new THREE.TorusKnotGeometry(
                            Math.random() * 10,
                            Math.random() * 2
                        ),

                        // 多面体
                        new THREE.DodecahedronGeometry(Math.random() * 10),
                        // 圆柱
                        new THREE.CylinderGeometry(
                            Math.random() * 10,
                            Math.random() * 10,
                            Math.random() * 20
                        ),
                        // 圆锥
                        new THREE.ConeGeometry(
                            Math.random() * 10,
                            Math.random() * 20
                        ),
                        // 方块盒子
                        new THREE.BoxGeometry(
                            Math.random() * 20,
                            Math.random() * 20,
                            Math.random() * 20
                        )
                    ][0],
                    new THREE.MeshBasicMaterial({
                        color: 0x00ff00,
                        opacity: 0.7,
                        emissive: 0x003300 // 发光颜色
                    })
                    // new THREE.MeshLambertMaterial({
                    //     color: "blue",
                    //     transparent: true,
                    //     opacity: 1
                    // })
                );
            })
            .nodeColor(node => {
                // return node.colors[node?.userData?.status || 0];
                return "blue";
            })
            .height(900) //画布高度
            .backgroundColor("rgba(0,0,0,0)") //画布背景色
            .showNavInfo(false) //禁用页脚
            .onNodeClick(node => {
                // console.log(RES.res1);
                // setTimeout(() => {

                let serviceNodes = [],
                    serviceLinks = [],
                    services = {};
                this.subNodes = RES.res1.data.data.serviceResourceObjectList.reduce(
                    (pre, cur, index) => {
                        let obj = {
                            id: `${node.id}_${index}`,
                            userData: {
                                status: node.userData.status,
                                ...cur
                            },
                            property: {
                                name: `${cur.serviceName}`
                            },
                            colors: ["red", "#00ccff", "orange"]
                        };

                        cur.ipv4s.forEach(ip => {
                            services[ip.key] ||= JSON.parse(JSON.stringify(ip));
                            services[ip.key].serArr
                                ? (services[ip.key].serArr = [
                                      ...services[ip.key].serArr,
                                      obj.id
                                  ])
                                : (services[ip.key].serArr = [obj.id]);
                        });
                        pre.push(obj);
                        return pre;
                    },
                    []
                );

                Object.keys(services).forEach(key => {
                    serviceNodes.push({
                        id: `${key}`,
                        userData: {
                            status: 1
                        },
                        property: {
                            name: `${services[key].value}-${key}`
                        },
                        colors: ["red", "#00ccff", "orange"]
                    });
                    services[key].serArr.forEach(ser => {
                        serviceLinks.push({
                            id: `links_${key}_${ser}`,
                            start: ser, //连线开始节点 id
                            end: key, //连线结束节点的id
                            type: "挂载", //线上文字
                            identity: null,
                            property: {},
                            source: ser, //连线开始节点 id
                            target: key, //连线开始节点 id
                            isShow: true, //是否显示线
                            group: 1
                        });
                    });
                });

                this.subLinks = RES.res1.data.data.serviceResourceObjectList.reduce(
                    (pre, cur, index) => {
                        let obj = {
                            id: `links_${node.id}_${index}`,
                            start: node.id, //连线开始节点 id
                            end: `${node.id}_${index}`, //连线结束节点的id
                            type: "调用", //线上文字
                            identity: null,
                            property: {},
                            source: node.id, //连线开始节点 id
                            target: `${node.id}_${index}`, //连线开始节点 id
                            isShow: true, //是否显示线
                            group: 1,
                            typeNum: 0
                        };
                        pre.push(obj);
                        return pre;
                    },
                    []
                );
                this.subNodes.push(...serviceNodes);
                this.subLinks.push(...serviceLinks);
                this.Graph.graphData({
                    nodes: [...this.nodes, ...this.subNodes],
                    links: [...this.links, ...this.subLinks]
                });
                // }, 20);
            })
            .nodeResolution(16)
            .cameraPosition(
                {
                    x: -60,
                    y: -120,
                    z: -60
                }, // new position
                {
                    x: 0,
                    y: 0,
                    z: 0
                }, // lookAt ({ x, y, z })
                3000 // ms transition duration
            ); //修改初始相机位置

        this.nodes = RES.res.data.data.accessTimes.reduce((pre, cur, index) => {
            let obj = {
                userData: { ...cur }
            };
            this.maxSize =
                this.maxSize < cur.accessTimes ? cur.accessTimes : this.maxSize;
            obj._accessTimes = cur.accessTimes;
            obj.id = index;
            obj.labels = ["N2"];
            obj.property = {
                name: cur.applicationFullName
            };
            obj.colors = ["red", "#00ccff", "orange"];
            pre.push(obj);

            return pre;
        }, []);
        this.nodes.unshift({
            id: 9999,
            name: "root",
            property: {
                name: "root"
            },
            colors: ["white", "white", "white"]
        });
        this.links = RES.res.data.data.accessTimes.reduce((pre, cur, index) => {
            let obj = {
                id: 2111, //线id
                start: 9999, //连线开始节点 id
                end: index, //连线结束节点的id
                type: "链接", //线上文字
                identity: null,
                property: {},
                source: 9999, //连线开始节点 id
                target: index, //连线开始节点 id
                isShow: true, //是否显示线
                group: 1,
                typeNum: 0
            };
            pre.push(obj);
            return pre;
        }, []);
        let N = 100;
        let gData = {
            nodes: [...Array(N).keys()].map(i => ({ id: i })),
            links: [...Array(N).keys()]
                .filter(id => id)
                .map(id => ({
                    source: id,
                    target: Math.round(Math.random() * (id - 1))
                }))
        };
        //    加入数据
        // this.Graph.graphData({
        //     nodes: [...this.nodes, ...this.subNodes],
        //     links: [...this.links, ...this.subLinks]
        // });
        this.Graph.graphData(gData);

        // this.node();
        // this.linkArrow();
        // 添加动画
        // this.linkText();
        // fit to canvas when engine stops
        // this.Graph.onEngineStop(() => this.Graph.zoomToFit(200));
        // this.HighPerformance();
    },
    methods: {
        // HighPerformance
        HighPerformance() {
            // if (this.bloomPass) return;
            this.RemovePerformance();
            // 添加阴影
            let { strength, radius, threshold } = this.bloomPassA;
            this.bloomPass = new UnrealBloomPass();
            this.bloomPass.strength = Number(strength);
            this.bloomPass.radius = Number(radius);
            this.bloomPass.threshold = Number(threshold);
            this.Graph.postProcessingComposer().addPass(this.bloomPass);
        },
        RemovePerformance() {
            this.bloomPass &&
                this.Graph.postProcessingComposer().removePass(this.bloomPass);
            this.bloomPass = null;
        },
        // 渲染节点
        node() {
            let _this = this;
            this.Graph.nodeThreeObject(node => {
                const nodeEl = document.createElement("div");
                nodeEl.textContent = node.property.name;
                nodeEl.style.color = "rgba(255, 255, 255)";
                nodeEl.className = "node-label";
                return new CSS2DObject(nodeEl);
            })
                .nodeThreeObjectExtend(false)
                .nodeOpacity(0.7)
                .nodeColor(node => {
                    // return node.colors[node?.userData?.status || 0];
                    return "blue";
                })
                .nodeVal(node => {
                    return 1 + (32 * node._accessTimes) / _this.maxSize;
                })
                // 节点文字
                .linkThreeObjectExtend(true);
        },
        // 线和线上文字
        linkText() {
            this.Graph.linkThreeObjectExtend(true)
                .linkThreeObject(link => {
                    const sprite = new SpriteText(`${link.type}`);
                    sprite.color = "rgba(255, 255, 255)";
                    sprite.textHeight = 1.5;
                    return sprite;
                })
                .linkPositionUpdate((sprite, { start, end }) => {
                    const middlePos = Object.assign(
                        ...["x", "y", "z"].map(c => ({
                            [c]: start[c] + (end[c] - start[c]) / 2 // calc middle point
                        }))
                    );
                    // Position sprite
                    Object.assign(sprite.position, middlePos);
                })
                // 曲线
                .linkCurvature(0.5)
                // 线颜色
                .linkColor(link => {
                    let obj = [...this.nodes, ...this.subNodes].find(item => {
                        return item.id == link.end;
                    });
                    return obj.colors[obj?.userData?.status || 0];
                })
                // 线宽度
                .linkWidth(link => 0.3)
                // .linkWidth(link => (this.highlightLinks.has(link) ? 1 : 0.3))
                .linkOpacity(0.7)
                .linkDirectionalParticles(5);
        },
        // 箭头
        linkArrow() {
            this.Graph.linkDirectionalArrowLength(2)
                .linkDirectionalArrowRelPos(1)
                .linkDirectionalParticleSpeed(0.005);
        }
    }
};
</script>

<style lang="less">
.graph-3d {
    width: 100%;
    height: 100%;
    background-color: rgb(7, 18, 56);
}
</style>
